/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package grafrajz.utils;

import java.util.ArrayList;

/**
 * Gráf reprezentáció. Tartalmaz a csúcsai listáját. Az élek nem itt tárolódnak, hanem a csúcsokon belül
 * @author adam_fejes_dell
 */
public class Graph{
    private ArrayList<Node> nodes;
    final private boolean IS_WEIGHTENED, IS_DIRECTED;
    protected Algorithms algo;

    public Graph(boolean isWeightened, boolean isDirected) {
        this.IS_WEIGHTENED = isWeightened;
        this.IS_DIRECTED = isDirected;
        this.algo = new Algorithms();
        nodes = new ArrayList<Node>();
    }
    


    /**
     * Csúcs hozzáadása
     * @return Igazzal tér vissza, ha sikeres a beszúrás
     * @param Egy csúcs objektumot vár paraméterül
    */
    public boolean addNode(Node n){
        if(!nodes.contains(n)){
            return nodes.add(n);
        }
        else
            return false;
    }
    
    /**
     * Él hozzáadása
     * @param source Kezdő csúcs
     * @param e Él (benne a célcsúcs)
     * @return Igazzal tér vissza ha sikeres a beszúrás
     */
    public boolean addEdge(Edge e){ 
        //if(true || IS_DIRECTED){
            if(nodes.contains(e.getSource()) && nodes.contains(e.getDest())){
                return nodes.get(nodes.indexOf(e.getSource())).addEdge(e);
            }
            else{
                return false;
            }
        /*}
        else{
            if(nodes.contains(e.getSource()) && nodes.contains(e.getDest())){
                nodes.get(nodes.indexOf(e.getSource())).addEdge(e);
                nodes.get(nodes.indexOf(e.getDest())).addEdge(new Edge(e.getDest(), e.getSource(), e.getWeight()));
                return true;
            }
            else{
                return false;
            }
        }*/
    }
    
    /**
     * Csúcs eltávolítása (nyilván az élekkel együtt)
     * @param n Egy csúcsot vár paraméterül
     * @return Igazzal tér vissza ha sikeres a törlés
     */
    public boolean removeNode(Node n){
        if(nodes.contains(n)){
            ////System.out.println("Node removed: " + n.getName());
            
            for(int i = 0; i < nodes.size(); i++){
                ArrayList<Edge> e = nodes.get(i).getEdges();
                for(int j = 0; j < e.size(); j++){
                    if(e.get(j).getDest().getName().equals(n.getName())){
                        removeEdge(e.get(j));
                    }
                }
            }
            
            return nodes.remove(n);
        }
        else
            return false;
    }
    
    /**
     * Él eltávolítása
     * @param e Egy élet vár paraméterül
     * @return Igazzal tér vissza ha sikeres a törlés
     */
    public boolean removeEdge(Edge e){
        int i = 0;
        boolean found = false;
        while(i < nodes.size() && !found){
            if(nodes.get(i).removeEdge(e)){ 
                found = true;
            }
            i++;
        }
        return found;
    }
    
    /**
     * Csúcsok száma
     * @return A gráfban lévő csűcsok számával tér vissza
     */
    public int getNodeCount(){
        return nodes.size();
    }
    
    /**
     * Élek száma
     * @return A gráfban lévő élek számával tér vissza
     */
    public int getEdgeCount(){
        int sum = 0;
        for(Node n : nodes){
            sum += n.getEdgeCount();
        }
        return sum;
    }

    /**
     * Irányított-e?
     * @return A gráf irányítottságával tér vissza
     */
    public boolean isDirected() {
        return IS_DIRECTED;
    }


    public boolean isWeightened() {
        return IS_WEIGHTENED;
    }

    public ArrayList<Node> getAllNodes() {
        return nodes;
    }
    
    public boolean containsNode(Node n){
        return nodes.contains(n);
    }
    
    public boolean containsEdge(Node sourceNode, Edge e){
        return nodes.get(nodes.indexOf(sourceNode)).containsEdge(e);
    }
    
    public ArrayList getAllEdges(){
        ArrayList<Edge> edges = new ArrayList<Edge>();
        
        for(Node node : nodes){
            edges.addAll(node.getEdges());
        }
        
        return edges;
    }
    
    /**
     * Igazzal tér vissza, ha az adott csúcshoz tartozik él 
     * @param n
     * @return 
     */
    public boolean hasEdges(Node n){
        /*if(!isDirected())
            return nodes.get(nodes.indexOf(n)).getEdges().size() > 0 ;
        else{
            for(int i = 0; i < nodes.size(); i++){
                ArrayList<Edge> edges = nodes.get(i).getEdges();
                for(int j = 0; j < nodes.get(i).getEdgeCount(); j++){
                    if(edges.get(j).getSource().getName().equals(n.getName()) || edges.get(j).getDest().getName().equals(n.getName()))
                            return true;
                }
            }
            
            return false;
        }*/
        
            ArrayList<Edge> edges = getAllEdges();
            for(Edge e : edges){
                if(e.getDest().getName().equals(n.getName()) || e.getSource().getName().equals(n.getName()))
                    return true;
            }
            
            return false;
        
        
    }
    
    public Node getNode(Node n){
        return nodes.get(nodes.indexOf(n));
    }
    
    public Node getFirstNode(){
        return nodes.get(0);
    }

    public Algorithms getAlgo() {
        return algo;
    }

    /**
     * Az adott csúcs szomszédos csúcsaivel tér vissza.
     * @param n
     * @return 
     */
    public ArrayList<Node> getNeighbours(Node n){
        ArrayList<Edge> edges;
        ArrayList<Node> neighbours = new ArrayList<Node>();
        
        ////System.out.println(n + " csúcs szomszédainak a keresése");

        edges = n.getEdges();
        ////System.out.println(n + " csúcs éleinek a száma: " + n.getEdgeCount());
        
        //Berakom azokat amik a saját listájában vannak, ha irányított, akkor ez így ellg is
        for(Edge e : edges){
            ////System.out.println("Új szomszéd: " + e.getDest());
            neighbours.add(getNode(e.getDest()));
        }

        //Ha nem irányított akkor kellenek azok is ahol célként szerepel
        if(!isDirected()){
            edges = getAllEdges();
            for(Edge e : edges){
                //A saját listáját nem vizsgáljuk újra
                if(!e.getSource().getName().equals(n.getName())){
                    if(e.getDest().getName().equals(n.getName()))
                        neighbours.add(getNode(e.getDest()));
                }



            }
        } 
        
        
        //////System.out.println("Ennyi szomszédot találtam: " + neighbours.size());
        return neighbours;
    }

    @Override
    public String toString() {
        return "Graph{" + "nodes=" + nodes + ", IS_WEIGHTENED=" + IS_WEIGHTENED + ", IS_DIRECTED=" + IS_DIRECTED + ", algo=" + algo + '}';
    }
    
    
    
    
    
    
}